package connection

import (
	"sync"
	"web_framework/model"
	"web_framework/websocket/v1/handler"

		"github.com/gorilla/websocket"
		log "github.com/sirupsen/logrus"
)

type Connection struct {
	//路由器sn,app  uid 绑定标识
	clientId string
	// 存放websocket连接
	wsConn *websocket.Conn
	// 用于存放数据
	inChan chan model.Request
	// 用于读取数据
	outChan   chan model.Response
	closeChan chan byte
	mutex     sync.Mutex
	// chan是否被关闭
	isClosed bool
}

//保存所有已经登录的连接
var RouterMaps = make(map[string]*Connection)

// 内部实现
func (conn *Connection) readLoop() {
	var (
		err error
		req model.Request
	)
	defer conn.Close()
	defer close(conn.inChan)
	// 并发读取数据
	go func() {

		for {
			if err = conn.wsConn.ReadJSON(&req); err != nil {

				conn.wsConn.WriteMessage(1, []byte(err.Error()))
				return
			}

			conn.inChan <- req
		}
	}()
	// 容易阻塞到这里，等待inChan有空闲的位置
	for {

		select {
		case <-conn.inChan:
			go route(req, conn)
		case <-conn.closeChan: // closeChan关闭的时候执行
			return
		//10秒客户端未发送数据关闭连接
		//case <-time.After(10 * time.Second):
		//	conn.wsConn.WriteMessage(1, []byte("readLoop 10s timeout close"))
		//	return
		}
	}

}

func WriteMessage(clientId string, msg model.Response) error {
	connection, ok := RouterMaps[clientId]
	if ok {
		go func(conn *Connection) {
			conn.outChan <- msg
		}(connection)
	}

	return nil
}

func (conn *Connection) writeLoop() {
	var (
		data model.Response
		err  error
	)
	defer conn.Close()
	defer close(conn.outChan)
	for {
		select {
		case data = <-conn.outChan:
		case <-conn.closeChan:
			return
		//10秒客户端未发送数据关闭连接
		//case <-time.After(10 * time.Second):
		//	conn.wsConn.WriteMessage(1, []byte("writeLoop 10s timeout close"))
		//	return
		}
		if err = conn.wsConn.WriteJSON(data); err != nil {
			conn.wsConn.WriteMessage(1, []byte(err.Error()))
			return
		}
	}

}

func route(data model.Request, conn *Connection) {

	mtype := data.Mtype
	//可以接受mtype > 1203
	if mtype <= 0 {
		return
	}

	handler.Holder.Start(mtype, data, conn.outChan, conn.wsConn, conn.clientId)
}

// 关闭连接的Api
func (conn *Connection) Close() {
	log.Info(conn.clientId + " connection closed")
	// 线程安全的Close，可以并发多次调用也叫做可重入的Close
	delete(RouterMaps ,conn.clientId)
	conn.wsConn.Close()
	conn.mutex.Lock()
	if !conn.isClosed {
		// 关闭chan,但是chan只能关闭一次
		close(conn.closeChan)
		conn.isClosed = true
	}
	conn.mutex.Unlock()
}

// 初始化长连接
func InitConnection(wsConn *websocket.Conn, clientId string) (conn *Connection, err error) {
	conn = &Connection{
		clientId:  clientId,
		wsConn:    wsConn,
		inChan:    make(chan model.Request, 100),
		outChan:   make(chan model.Response, 100),
		closeChan: make(chan byte, 1),
	}

	// 启动读协程
	go conn.readLoop()

	// 启动写协程
	go conn.writeLoop()

	return
}
